package com.retlife.tvshow.serial_port.bike

import android.serialport.BuildConfig
import com.retlife.tvshow.serial_port.BaseSerialManage
import com.retlife.tvshow.serial_port.bike.DecodeData.Companion.NUT_CYCLES_CLEAR_ID
import com.retlife.tvshow.serial_port.bike.DecodeData.Companion.NUT_ISO_POSITION_START
import com.retlife.tvshow.serial_port.bike.DecodeData.Companion.NUT_ISO_POSITION_STOP
import com.retlife.tvshow.serial_port.bike.DecodeData.Companion.NUT_ISO_SET_SPEED
import com.retlife.tvshow.serial_port.bike.DecodeData.Companion.NUT_ISO_TRIGGER_CCW
import com.retlife.tvshow.serial_port.bike.DecodeData.Companion.NUT_ISO_TRIGGER_CW
import com.retlife.tvshow.serial_port.bike.DecodeData.Companion.NUT_PAUSE_ID
import com.retlife.tvshow.serial_port.bike.DecodeData.Companion.NUT_POWER1_SET_LOAD_ID
import com.retlife.tvshow.serial_port.bike.DecodeData.Companion.NUT_POWER2_SET_LOAD_ID
import com.retlife.tvshow.serial_port.bike.DecodeData.Companion.NUT_POWER_STATUS_CODE
import com.retlife.tvshow.serial_port.bike.DecodeData.Companion.NUT_POWER_SWITCH_ID
import com.retlife.tvshow.serial_port.bike.DecodeData.Companion.NUT_PROGRAM_ID
import com.retlife.tvshow.serial_port.bike.DecodeData.Companion.NUT_SEND_SAMPLE_TIME_ID
import com.retlife.tvshow.serial_port.bike.DecodeData.Companion.NUT_SET_BUF_SIZE_ID
import com.retlife.tvshow.serial_port.bike.DecodeData.Companion.NUT_SET_POWER_ID
import com.retlife.tvshow.serial_port.bike.DecodeData.Companion.NUT_SET_SAMPLE
import com.retlife.tvshow.serial_port.bike.DecodeData.Companion.NUT_SET_TORQUE_ID
import com.retlife.tvshow.serial_port.bike.DecodeData.Companion.NUT_START_ID
import com.retlife.tvshow.serial_port.bike.DecodeData.Companion.NUT_STOP_ID
import com.retlife.tvshow.serial_port.bike.DecodeData.Companion.NUT_TORQUE_100HZ_ID
import com.retlife.tvshow.serial_port.bike.DecodeData.Companion.NUT_TORQUE_10HZ_ID
import com.retlife.tvshow.serial_port.bike.DecodeData.Companion.NUT_TORQUE_200HZ_ID
import com.retlife.tvshow.serial_port.bike.DecodeData.Companion.NUT_TORQUE_ASK_ID
import com.retlife.tvshow.serial_port.bike.DecodeData.Companion.NUT_TORQUE_RESET_ID
import com.retlife.tvshow.serial_port.bike.DecodeData.Companion.NUT_TORQUE_STOP_ID

class SerialBikeManager(s: String) {
    private val serialManage: BaseSerialManage

    init {
        serialManage = BaseSerialManage(s, 9600, true, 0, 8, 0, 0, BaseSerialBikeReceiver())
    }

    var isOpen: Boolean = false
        private set

    fun open(): Boolean {
        isOpen = serialManage.open()
        if (isOpen && BuildConfig.DEBUG) {
//            serialManage.startTest();
        }
        return isOpen
    }

    fun startCmd() {
        sendRequest1(NUT_START_ID)
    }

    fun pauseCmd() {
        sendRequest1(NUT_PAUSE_ID)
    }

    fun stopCmd() {
        sendRequest1(NUT_STOP_ID)
    }

    fun setTorque(data: Int) {
        sendRequest2(data, NUT_SET_TORQUE_ID)
    }

    fun setPower(data: Int) {
        sendRequest2(data, NUT_SET_POWER_ID)
    }

    fun setBufferSize(data: Int) {
        sendRequest2(data, NUT_SET_BUF_SIZE_ID)
    }

    fun setSendDelayMs(data: Int) {
        sendRequest2(data, NUT_SEND_SAMPLE_TIME_ID)
    }

    fun setVotageCode2(data: Int) {
        sendRequest2(data, NUT_POWER2_SET_LOAD_ID)
    }

    fun setVotageCode(data: Int) {
        sendRequest2(data, NUT_POWER1_SET_LOAD_ID)
    }

    fun setSampleRate(data: Int) {
        sendRequest2(data, NUT_SET_SAMPLE)
    }

    fun sendIsoSpeed(data: Int) {
        sendRequest2(data, NUT_ISO_SET_SPEED)
    }

    fun sendIsoStartPosition(data: Int) {
        sendRequest2(data, NUT_ISO_POSITION_START)
    }

    fun sendTriggerCW(data: Int) {
        sendRequest2(data, NUT_ISO_TRIGGER_CW)
    }

    fun sendIsoStopPosition(data: Int) {
        sendRequest2(data, NUT_ISO_POSITION_STOP)
    }

    fun sendTriggerCCW(data: Int) {
        sendRequest2(data, NUT_ISO_TRIGGER_CCW)
    }

    fun sendPowerSwitchOnOff(id: Int, status: Int) {
        sendRequest2(id shl 8 or status, NUT_POWER_SWITCH_ID)
    }

    fun sendProgramID(programId: Int, steps: Int) {
        sendRequest2(programId shl 8 or steps, NUT_PROGRAM_ID)
    }

    fun sendBikeClearCircles() {
        sendRequest1(NUT_POWER_STATUS_CODE)
    }

    fun askPowerStatus() {
        sendRequest1(NUT_CYCLES_CLEAR_ID)
    }

    fun sendBikeRequire200Hz() {
        sendRequest1(NUT_TORQUE_200HZ_ID)
    }

    fun sendBikeRequire10Hz() {
        sendRequest1(NUT_TORQUE_10HZ_ID)
    }

    fun sendBikeRequire100Hz() {
        sendRequest1(NUT_TORQUE_100HZ_ID)
    }

    fun sendBikeReset() {
        sendRequest1(NUT_TORQUE_RESET_ID)
    }

    fun sendBikeAskData() {
        sendRequest1(NUT_TORQUE_ASK_ID)
    }

    fun sendBikeStop() {
        sendRequest1(NUT_TORQUE_STOP_ID)
    }

    private fun sendRequest1(b: Int) {
        val bytes = ByteArray(7)
        bytes[0] = 0xa5.toByte()
        bytes[1] = 0x5a
        bytes[2] = 4
        bytes[3] = (b shr 8).toByte()
        bytes[4] = (b and 0xff).toByte()
        val s: Int = crc(bytes)
        bytes[5] = (s shr 8).toByte()
        bytes[6] = (s and 0xff).toByte()
        serialManage.send(bytes)
    }

    private fun sendRequest2(data: Int, cmd: Int) {
        val bytes = ByteArray(9)
        bytes[0] = 0xa5.toByte()
        bytes[1] = 0x5a
        bytes[2] = 6
        bytes[3] = (cmd shr 8).toByte()
        bytes[4] = (cmd and 0xff).toByte()
        bytes[5] = (data shr 8).toByte()
        bytes[6] = (data and 0xff).toByte()
        val s: Int = crc(bytes)
        bytes[7] = (s shr 8).toByte()
        bytes[8] = (s and 0xff).toByte()
        serialManage.send(bytes)
    }

    private fun sendBikeSystemSetting(data: Int, childCmd: Int) {
        val bytes = ByteArray(11)
        bytes[0] = 0xa5.toByte()
        bytes[1] = 0x5a
        bytes[2] = 8
        bytes[3] = (DecodeData.NUT_BIKE_SYSTEM_SETTING_CODE shr 8).toByte()
        bytes[4] = (DecodeData.NUT_BIKE_SYSTEM_SETTING_CODE and 0xff).toByte()
        bytes[5] = (childCmd shr 8).toByte()
        bytes[6] = (childCmd and 0xff).toByte()
        bytes[7] = (data shr 8).toByte()
        bytes[8] = (data and 0xff).toByte()
        val s: Int = crc(bytes)
        bytes[9] = (s shr 8).toByte()
        bytes[10] = (s and 0xff).toByte()
        serialManage.send(bytes)
    }

    companion object {
        /* var instance: SerialBikeManager? = null
             get() {
                 if (field == null) {
                     field = SerialBikeManager()
                 }
                 return field
             }
             private set*/

        fun crc(bytes: ByteArray): Int {
            var crc = 0xffff
            var i = 3
            while (i < bytes.size - 2) {
                crc = crc xor (bytes[i].toInt() and 0xff)
                var j = 0
                while (j < 8) {
                    crc = if ((crc and 0x01) == 0x01) {
                        (crc shr 1) xor 0xa001
                    } else {
                        crc shr 1
                    }
                    j++
                }
                i++
            }
            return crc
        }
    }
}
